package com.mc.fastkit.utils

import android.util.Base64
import java.security.InvalidParameterException
import java.security.KeyFactory
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.MessageDigest
import java.security.PrivateKey
import java.security.PublicKey
import java.security.SecureRandom
import java.security.spec.AlgorithmParameterSpec
import java.security.spec.InvalidKeySpecException
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec

/**
 * 加密工具类
 * @author: MasterChan
 * @date: 2022-6-23 21:05
 */
object EncodeUtils {

    fun encode2Base64(input: String, flags: Int = Base64.NO_WRAP): ByteArray {
        return encode2Base64(input.toByteArray(), flags)
    }

    fun encode2Base64(input: ByteArray, flags: Int = Base64.NO_WRAP): ByteArray {
        return Base64.encode(input, flags)
    }

    fun encode2Base64String(input: String, flags: Int = Base64.NO_WRAP): String {
        return encode2Base64String(input.toByteArray(), flags)
    }

    fun encode2Base64String(data: ByteArray, flags: Int = Base64.NO_WRAP): String {
        return Base64.encodeToString(data, flags)
    }

    fun encode2Md5(data: String): ByteArray {
        return encode2Md5(data.toByteArray())
    }

    fun encode2Md5(data: ByteArray): ByteArray {
        return digestEncryption(data, "MD5")
    }

    fun encode2Sha1(data: String): ByteArray {
        return encode2Sha1(data.toByteArray())
    }

    fun encode2Sha1(data: ByteArray): ByteArray {
        return digestEncryption(data, "SHA-1")
    }

    fun encode2Sha224(data: String): ByteArray {
        return encode2Sha224(data.toByteArray())
    }

    fun encode2Sha224(data: ByteArray): ByteArray {
        return digestEncryption(data, "SHA-224")
    }

    fun encode2Sha256(data: String): ByteArray {
        return encode2Sha256(data.toByteArray())
    }

    fun encode2Sha256(data: ByteArray): ByteArray {
        return digestEncryption(data, "SHA-256")
    }

    fun encode2Sha512(data: String): ByteArray {
        return encode2Sha512(data.toByteArray())
    }

    fun encode2Sha512(data: ByteArray): ByteArray {
        return digestEncryption(data, "SHA-512")
    }

    /**
     * 加密
     * @param data 加密数据
     * @param algorithm 加密算法：MD5,SHA-1,SHA-224,SHA-256,SHA-384,SHA-512等
     * @return 16进制字符串
     */
    fun digestEncryption(data: ByteArray, algorithm: String): ByteArray {
        val messageDigest = MessageDigest.getInstance(algorithm)
        messageDigest.update(data)
        return messageDigest.digest()
    }

    fun encode2Aes(
        data: String,
        key: String,
        transformation: String = "AES/ECB/NoPadding"
    ): ByteArray {
        return encode2Aes(data.toByteArray(), key.toByteArray(), transformation)
    }

    /**
     * AES加密
     * @param data ByteArray
     * @param key 密钥，长度为16的倍数
     * @param transformation: String
     * @return ByteArray
     */
    fun encode2Aes(
        data: ByteArray,
        key: ByteArray,
        transformation: String = "AES/ECB/NoPadding"
    ): ByteArray {
        return encodeCipher(data, key, "AES", transformation)
    }

    fun encode2Des(
        data: String,
        key: String,
        transformation: String = "DES/ECB/NoPadding"
    ): ByteArray {
        return encode2Des(data.toByteArray(), key.toByteArray(), transformation)
    }

    /**
     * des加密
     * @param data ByteArray
     * @param key 密钥，长度固定为8
     * @param transformation: String
     * @return ByteArray
     */
    fun encode2Des(
        data: ByteArray,
        key: ByteArray,
        transformation: String = "DES/ECB/NoPadding"
    ): ByteArray {
        return encodeCipher(data, key, "DES", transformation)
    }

    /**
     * 加密
     * @param data 加密数据
     * @param secretKey 密钥
     * @param algorithm 算法：AES、DES
     * @param transformation String
     * @return ByteArray
     */
    fun encodeCipher(
        data: ByteArray,
        secretKey: ByteArray,
        algorithm: String,
        transformation: String,
        random: SecureRandom = SecureRandom()
    ): ByteArray {
        try {
            val keySpec = SecretKeySpec(secretKey, algorithm)
            val cipher = Cipher.getInstance(transformation)
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, random)
            return cipher.doFinal(data)
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return byteArrayOf()
    }

    /**
     * 加密
     * @param data 加密数据
     * @param secretKey 密钥
     * @param algorithm 算法：AES、DES
     * @param transformation String
     * @param params AlgorithmParameterSpec
     * @return ByteArray
     */
    fun encodeCipher(
        data: ByteArray,
        secretKey: ByteArray,
        algorithm: String,
        transformation: String,
        params: AlgorithmParameterSpec
    ): ByteArray {
        try {
            val keySpec = SecretKeySpec(secretKey, algorithm)
            val cipher = Cipher.getInstance(transformation)
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, params)
            return cipher.doFinal(data)
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return byteArrayOf()
    }

    /**
     * 生成RSA密钥对
     * @param keySize Int
     * @return KeyPair
     * @throws InvalidParameterException
     */
    fun generateKeyPair(keySize: Int = 1024): KeyPair {
        return KeyPairGenerator.getInstance("RSA").apply { initialize(keySize) }.generateKeyPair()
    }

    /**
     * 获取RSA秘钥
     * @param key String
     * @return PrivateKey
     * @throws InvalidKeySpecException
     */
    fun getRsaPrivateKey(key: String): PrivateKey {
        return getRsaPrivateKey(key.toByteArray())
    }

    /**
     * 获取RSA秘钥
     * @param key ByteArray
     * @return PrivateKey
     * @throws InvalidKeySpecException
     */
    fun getRsaPrivateKey(key: ByteArray): PrivateKey {
        return KeyFactory.getInstance("RSA").generatePrivate(PKCS8EncodedKeySpec(key))
    }

    /**
     * 获取RSA公钥
     * @param key String
     * @return PublicKey
     * @throws InvalidKeySpecException
     */
    fun getRsaPublicKey(key: String): PublicKey {
        return getRsaPublicKey(key.toByteArray())
    }

    /**
     * 获取RSA公钥
     * @param key ByteArray
     * @return PublicKey
     * @throws InvalidKeySpecException
     */
    fun getRsaPublicKey(key: ByteArray): PublicKey {
        return KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(key))
    }

    /**
     * RSA加密
     * @param data ByteArray
     * @param publicKey PublicKey
     * @return ByteArray
     */
    fun rsa(data: ByteArray, publicKey: PublicKey, transformation: String = "RSA"): ByteArray {
        return try {
            val cipher = Cipher.getInstance(transformation)
            cipher.init(Cipher.ENCRYPT_MODE, publicKey)
            val blockSize = cipher.blockSize
            val outputSize = cipher.getOutputSize(data.size)
            val blocksSize = if (data.size % blockSize == 0) {
                data.size / blockSize
            } else {
                data.size / blockSize + 1
            }
            val output = ByteArray(outputSize * blocksSize)
            var i = 0
            while (data.size - i * blockSize > 0) {
                if (data.size - i * blockSize > blockSize) {
                    cipher.doFinal(data, i * blockSize, blockSize, output, i * outputSize)
                } else {
                    cipher.doFinal(
                        data, i * blockSize, data.size - i * blockSize, output, i * outputSize
                    )
                }
                i++
            }
            output
        } catch (e: Exception) {
            e.printStackTrace()
            byteArrayOf()
        }
    }
}